package com.beyondsoft.dtc.mobile.automation.base;

import com.beyondsoft.dtc.mobile.automation.model.*;
import com.beyondsoft.dtc.mobile.automation.model.AppLog.Item;
import com.beyondsoft.dtc.mobile.automation.uiautomator.model.Coordinate;
import com.beyondsoft.dtc.mobile.automation.uiautomator.model.UiDumpModel;
import com.beyondsoft.dtc.mobile.automation.uiautomator.service.UiAutomatorHandlerService;
import com.beyondsoft.dtc.mobile.automation.util.*;
import com.beyondsoft.dtc.mobile.automation.util.ShellUtil.CommandResult;
import com.google.gson.Gson;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import java.io.*;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by Robin on 3/11/2016.
 */
public abstract class BaseExecutor extends Thread implements GlobalConstants {
    protected final Logger logger = LogManager.getLogger(BaseExecutor.class);
    protected final AtomicBoolean stopFlag = new AtomicBoolean(false);
    protected final AtomicBoolean startAppFlag = new AtomicBoolean(false);
    final private AtomicInteger lock;
    protected AtomicBoolean installStopFlag = new AtomicBoolean(false);
    // android5.0.2安装以及开始运行时相应对话框处理
    protected AtomicBoolean startMonkeyTest = new AtomicBoolean(false);

    protected int sdkVersion = 16;
    protected String taskId;
    protected String deviceRootPath;
    protected String connectAddress;
    protected ApkFile apkFile;
    protected Device device;
    protected String token;
    protected TaskResult taskResult = new TaskResult();
    protected String removedPrefix;
    private String userName = "TEST_NAME";
    private String password = "TEST_PSWD";
    private ArrayList<String> pids = new ArrayList<String>();
    private int unlockType = 0; // record unlock screen state
    protected AppLog appLog;
    private String[] dispx; // 手机分辨率

    protected UiAutomatorHandlerService service;
    protected String adbPath = GlobalConstants.ADB_COMMAND;

    public BaseExecutor(String taskId, String deviceRootPath,
                        AtomicInteger lock, ApkFile apkFile, Device device, String token) {
        this.taskId = taskId;
        this.deviceRootPath = deviceRootPath;
        this.lock = lock;
        this.apkFile = apkFile;
        this.device = device;
        this.device.setTaskId(taskId);
        this.connectAddress = device.getConnectAddress();
        this.token = token;
        this.removedPrefix = GlobalConfig.getInstance().getWorkDir();
        this.appLog = new AppLog();
        service = new UiAutomatorHandlerService(
                adbPath, connectAddress);
        taskResult.setTaskId(taskId);
        taskResult.setDeviceId(device.getDeviceId());
        taskResult.setAppName(apkFile.getName());
        taskResult.setAppIcon(StringUtil.removePrefix(
                apkFile.getIconLocalFilePath(), removedPrefix));
        taskResult.setAppSize(apkFile.getSize());

        // create work dir if needed.
        FileUtil.createDirs(deviceRootPath);
    }

    /**
     * check and connect/disconnect to if it is a remote device without local
     * USB connection.
     *
     * @param remoteIP remote device ip:port
     * @param connect  true connect from remote ip:port
     * @return true success, false failure
     */
    protected boolean toggleToRemoteADBServer(String remoteIP, boolean connect) {
        String[] command = {adbPath, "devices", "-l"};
        ShellUtil.execCommand(command); // just want to trigger local adb server
        // be started
        command = new String[]{adbPath, (connect ? "connect" : "disconnect"),
                remoteIP};
        CommandResult commandResult = ShellUtil.execCommand(command);
        if (!commandResult.isCommandSucceeded()) {
            taskResult.setAppRunErrorDesc(commandResult.getResultMsg());
            return false;
        }

        if (connect) {
            try {
                Thread.sleep(5000); // delay few seconds, since remote connect
                // is async mode and it may need take more time.
            } catch (InterruptedException e) {
            }
        }

        return true;
    }

    /**
     * get the focuse Activity
     *
     * @return
     */
    public String getCurrentActvity(String deviceSign) {
        // adb shell dumpsys activity | grep "mFocusedActivity"
        String[] command = {GlobalConstants.ADB_COMMAND, "-s", deviceSign,
                "shell", "dumpsys", "activity | grep \"mFocusedActivity\""};
        CommandResult commandResult = ShellUtil.execCommand(command);
        return commandResult.getResultMsg();
    }

    /**
     * check target device is online or not.
     *
     * @return true online, false offline
     */
    Boolean isFirstCheckDevice = true;

    protected boolean checkDevice() {
        CommandResult commandResult = null;
        int i = 0;
        for (; i < 3; i++) {
            String[] command = {adbPath, "devices"};
            commandResult = ShellUtil.execCommandNoLog(command);
            // command execut success , the line of result more then two
            if (commandResult.isCommandSucceeded()
                    && commandResult.getResultMsg().split("\n").length >= 2) {
                break;
            }
            try {
                sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isFirstCheckDevice = false;

        if (!commandResult.isCommandSucceeded()) {
            return false;
        }
        if (i == 3) {
            logger.error("check device 3 times, resultMsg : /n"
                    + commandResult.getResultMsg());
        }

        try {
            String[] results = commandResult.getResultMsg().split(
                    GlobalConstants.SYMBOL_CRLF);
            for (String line : results) {
                if (line.contains("List of devices")
                        || StringUtil.isEmpty(line)) {
                    continue;
                }
                line = line.replace(GlobalConstants.SYMBOL_TAB, " ");
                String deviceNum = line.substring(0, line.indexOf(" "));
                if (deviceNum.equals(connectAddress.trim())
                        && line.contains("device")) {
                    return true;
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return false;
    }

    protected boolean checkDeviceWithStatusSet( boolean isFirst) {

        boolean ret = false;
        for (int i = 0; i < 3; i++) {
            ret = checkDevice();
            if (ret) {
                return ret;
            }
        }
        taskResult.setAppInstall(AutomationResult.FAILURE.getValue());
        taskResult.setAppRunErrorDesc("device " + connectAddress + " is offline" + (isFirst? "!" : "on running!") );
        return ret;
    }

    /**
     * check screen is on or off.
     *
     * @return true screen is on, false off.
     */
    protected boolean isScreenOn() {
        String[] command = {
                "sh",
                "-c",
                adbPath + " -s " + connectAddress
                        + " shell dumpsys input_method | grep -i mActive"};
        CommandResult commandResult = ShellUtil.execCommand(command);
        return commandResult.isCommandSucceeded()
                && commandResult.getResultMsg().contains("mActive=true");
    }

    /**
     * check and set screen on.
     *
     * @return true screen turned on, false failed
     */
    protected boolean turnOnScreen() {
        if (isScreenOn()) {
            return true;
        }
        String[] command = {adbPath, "-s", connectAddress, "shell",
                "input keyevent 26"}; // power on/off code
        CommandResult commandResult = ShellUtil.execCommand(command);
        return commandResult.isCommandSucceeded();
    }


    /**
     * clear all logs from device
     *
     * @return true success, false failure
     */
    protected void clearLogcat() {
        if (!checkDevice()) {
            return;
        }
        String[] command = {adbPath, "-s", connectAddress, "logcat", "-c"};
        ShellUtil.execCommand(command);
    }

    protected void clearDevice() {
        String[] command = {adbPath, "-s", connectAddress, "shell",
                "am broadcast -a clear.device"};
        ShellUtil.execCommandNoWait(command);
    }

    /**
     * dump android logs from device to local file.
     *
     * @return true success, false failure
     */
    protected boolean collectLogcat(String logFile) {
        if (!checkDevice()) {
            return false;
        }
        String[] command = {
                "sh",
                "-c",
                adbPath + " -s " + connectAddress + " logcat  -v time -d >> " + logFile};
        CommandResult commandResult = ShellUtil.execCommand(command,false);
        return commandResult.isCommandSucceeded();
    }

    /**
     * simply use echo command print log to file.
     *
     * @param content log content
     * @param logFile log file full path
     */
    protected void echoMsgToLog(String content, String logFile) {
        String msg = "\n=============================================\n"
                + content + "\n=============================================\n";

        String[] commandLog = {"sh", "-c", "echo '" + msg + "' >> " + logFile};
        ShellUtil.execCommandNoLog(commandLog);
    }

    /**
     * install apk file.
     *
     * @return true success, false failure
     */
    protected boolean installApk() {
        if (!checkDeviceWithStatusSet(true)) {
            return false;
        }
        clearLogcat();
        String[] command = null;
        CommandResult commandResult = null;
        boolean ret = false;
        String installLog = deviceRootPath + "install.log";
        String tag = "===== Installation Failure =====\n";
        int index = 0;
        int i = 0;
        logger.info(device.getConnectAddress() + " install cmd: start ");
        for (; i < 4; i++) {
            // apk install
            long installOld = System.currentTimeMillis();
            command = new String[]{adbPath, "-s", connectAddress, "install",
                    "-r", apkFile.getLocalFilePath()};
            commandResult = ShellUtil.execCommand(command);
            long installNow = System.currentTimeMillis();
            taskResult.setInstallDuration((int) (installNow - installOld));

            if (commandResult.isCommandTimeOut()) {
                break;
            }
            CommandResult result = ShellUtil.execCommand(new String[]{"adb",
                    "-s", connectAddress, "shell", "pm", "list", "package"});

            boolean contains = result.getResultMsg().contains(apkFile.getPackageName());
            if (contains) {
                break;
            } else {
                taskResult.setAppRunErrorDesc("install fail");
                continue;
            }
        }

        if (i == 4) {
            index = commandResult.getResultMsg().indexOf("Failure");
            if (index == -1) {
                index = commandResult.getResultMsg().indexOf("failed");
            }
            String errorDesc = tag
                    + commandResult.getResultMsg().substring(index);
            if (errorDesc.contains("INSTALL_FAILED_INSUFFICIENT_STORAGE")) {
                errorDesc += ":手机空间不足";
            }
            taskResult.setAppRunErrorDesc(errorDesc);
            taskResult.setAppRunErrorLog(StringUtil.removePrefix(installLog,
                    removedPrefix));
            taskResult.setInstall_error_reason(errorDesc);

        } else if (commandResult.isCommandTimeOut()) {
            taskResult.setAppRunErrorDesc(tag + " install timeout");
            taskResult.setAppRunErrorLog(StringUtil.removePrefix(installLog,
                    removedPrefix));
            taskResult.setInstall_error_reason(tag + " install timeout");
        } else {
            ret = true;
            tag = "===== Installation Success =====\n";
        }

        logger.info(device.getConnectAddress() + " install cmd: over");
        taskResult.setAppInstallLog(StringUtil.removePrefix(installLog,
                removedPrefix));
        taskResult.setAppInstall(ret ? AutomationResult.SUCCESS
                .getValue() : AutomationResult.FAILURE
                .getValue());

        if (ret) {
            ExlFileUtil.saveInfo(taskId, connectAddress, "tag");
        }
        String msg = tag + commandResult.getResultMsg();
        echoMsgToLog(msg, installLog);
        collectLogcat(installLog);
        return ret;
    }

    /**
     * uninstall app.
     *
     * @return true success, false failure
     */
    protected boolean uninstallApk(boolean needLog) {
        // TODO: 2016/11/16 添加clear命令
        clearLogcat();

        String[] command = {adbPath, "-s", connectAddress, "shell",
                "pm clear ", apkFile.getPackageName()};
        ShellUtil.execCommandNoWait(command);
        command = new String[]{adbPath, "-s", connectAddress, "uninstall",
                apkFile.getPackageName()};
        CommandResult commandResult = ShellUtil
                .execCommandWithTimeout(command, true, 15 * 1000);

        if (!needLog) {
            return true;
        }

        boolean ret = false;
        String unInstallLog = deviceRootPath + "uninstall.log";
        String tag = "===== UnInstallation Failure =====\n";
        int index = commandResult.getResultMsg().indexOf("Failure");
        if (index >= 0) {
            String errorDesc = commandResult.getResultMsg().substring(index);
            taskResult.setAppRunErrorDesc(tag + errorDesc);
            taskResult.setAppRunErrorLog(StringUtil.removePrefix(unInstallLog,
                    removedPrefix));
            taskResult.setUninstall_error_reason(commandResult.getResultMsg());
        } else {
            ret = true;
            tag = "===== UnInstallation Success =====\n";
        }
        taskResult.setAppUninstallLog(StringUtil.removePrefix(unInstallLog,
                removedPrefix));
        taskResult
                .setAppUninstall(ret ? AutomationResult.SUCCESS
                        .getValue() : AutomationResult.FAILURE
                        .getValue());
        // try to append more error info to log
        String msg = tag + commandResult.getResultMsg();
        msg = msg.substring(tag.lastIndexOf("%") + 2);
        echoMsgToLog(msg, unInstallLog);
        collectLogcat(unInstallLog);
        return ret;
    }

    /**
     * start app.
     *
     * @return true success, false failure
     */
    protected boolean startApp(boolean isCollectionLog) {
        if (!checkDeviceWithStatusSet(false)) {
            return false;
        }
        String startLog = deviceRootPath + "start.log";
        String tag = "===== Start App Failure =====\n";
        CommandResult commandResult = null;
        String errorDesc = "";
        int i = 0;
        boolean ret = false;
        long startTime = 0l;
        long endTime = 0l;
        for (; i < 3; i++) {
            startTime = System.currentTimeMillis();

            String[] command = {adbPath, "-s", connectAddress, "shell",
                    "am start ",
                    apkFile.getPackageName() + "/" + apkFile.getActivityName()};
            commandResult = ShellUtil.execCommand(command);
            endTime = System.currentTimeMillis();

            int index = commandResult.getResultMsg().indexOf("Error");
            if (index < 0) {
                break;
            } else {
                errorDesc = commandResult.getResultMsg().substring(index);
            }
        }
        if (i == 3) {
            taskResult.setAppRunErrorDesc(tag + errorDesc);
            taskResult.setAppRunErrorLog(StringUtil.removePrefix(startLog,
                    removedPrefix));
            taskResult.setStart_error_reason(commandResult.getResultMsg());
        } else {
            ret = true;
            tag = "===== Start App Success =====\n";
            monitorAppAndRecordPid();
        }
        taskResult.setAppStart(ret ? AutomationResult.SUCCESS
                .getValue() : AutomationResult.FAILURE
                .getValue());
        taskResult.setStartTime(startTime);
        taskResult.setStartDuration((int) (endTime - startTime));

        if (isCollectionLog) {
            // try to append more error info to log
            String msg = tag + commandResult.getResultMsg();
            echoMsgToLog(msg, startLog);
            collectLogcat(startLog);
        }
        return ret;
    }

    protected boolean stopApp() {
        String[] command = {adbPath, "-s", connectAddress, "shell",
                "am force-stop", apkFile.getPackageName()};
        CommandResult commandResult = ShellUtil.execCommand(command);
        return commandResult.isCommandSucceeded();
    }

    /**
     * collect Anr,Crash,Exception log to local files
     *
     * @return true success, false failure
     */
    protected void collectAnrCrashExceptionLog(String runLog, String runAppLog, String exceptionLog, String crashLog, String anrLog) {
        if (!checkDevice()) {
            return;
        }
        try {
            String[] command = {
                    "sh",
                    "-c",
                    adbPath + " -s " + connectAddress
                            + " logcat  -v time  -d > " + runLog};
            logger.debug(device.getConnectAddress() + "  {}"+"command:"
                    + Arrays.toString(command));
            CommandResult commandResult = ShellUtil
                    .execCommandNoLog(command);
            if (commandResult.isCommandSucceeded()) {
                String pidStr = "";
                for (int i = 0; i < pids.size(); i++) {
                    if (i == 0) {
                        pidStr += "'";
                    }
                    pidStr += pids.get(i);
                    if (i == pids.size() - 1) {
                        pidStr += "'";
                        break;
                    }
                    pidStr += "\\|";
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                String cmdStr = null;
                String grepPid = "";
                logger.info(device.getConnectAddress() + " grepPid:" + grepPid);
                if (pidStr.length() != 0) {
                    grepPid = "grep " + pidStr;
                    cmdStr = "grep " + pidStr + " " + runLog + ">" + runAppLog;
                } else {
                    cmdStr = "grep " + pidStr + " " + runLog + ">" +
                            runAppLog;
                    FileUtil.copyFile(new File(runLog), new File(runAppLog));
                }
                String[] command0 = {"sh", "-c", cmdStr};
                logger.info(device.getConnectAddress() + " command0:"
                        + Arrays.toString(command0));
                 ShellUtil.execCommandNoLog(command0);
                String[] command1 = {"sh", "-c",
                        "grep 'AndroidRuntime' " + runAppLog + ">" + crashLog};
                logger.info(device.getConnectAddress() + " command1:"
                        + Arrays.toString(command1));

                commandResult = ShellUtil.execCommandNoLog(command1);
                logger.info(device.getConnectAddress() + " command1:isok:"
                        + commandResult.isCommandSucceeded());

                String[] command2 = {"sh", "-c",
                        "grep 'System.err' " + runAppLog + ">" + exceptionLog};
                logger.info(device.getConnectAddress() + " command2:"
                        + Arrays.toString(command2));
                commandResult = ShellUtil.execCommandNoLog(command2);
                logger.info(device.getConnectAddress() + " command2:isok:"
                        + commandResult.isCommandSucceeded());

                String[] command3 = {"sh", "-c", "grep 'ANR in' " + runLog};
                logger.info(device.getConnectAddress() + " command3:"
                        + Arrays.toString(command3));
                commandResult = ShellUtil.execCommandNoLog(command3);
                if (commandResult.isCommandSucceeded()
                        && commandResult.getResultMsg().trim().length() != 0) {
                    String[] command4 = {
                            "sh",
                            "-c",
                            adbPath + " -s " + connectAddress
                                    + " pull /data/anr/traces.txt "
                                    + deviceRootPath};
                    commandResult = ShellUtil.execCommand(command4);
                    if(commandResult.isCommandSucceeded()){
                        logger.error(connectAddress + " collection traces log success!");
                    }
                }

                generateLogReportEntity(runLog, runAppLog, anrLog);

                // 判定以下aapLog中是否有crash和anr是否是空，如果空，那么把monkey结果中过滤出来的crash，anr信息添加进去（这个可能是个bug）
                // 不过这种方式推荐（应该认真查找出现这种两方面不一致的问题所在进行解决）
                // 话是这么说，可是monkey结果中的信息和logcat的信息不一致也是正常的，哈h
                if (appLog.getCrashs() == null
                        || appLog.getCrashs().size() == 0) {
                    int appRun = taskResult.getAppRun();
                    if (appRun == AutomationResult.CRASH
                            .getValue()) {
                        Item item = new Item();
                        item.name = taskResult.getAppRunErrorDesc();
                        item.detail = taskResult.getAppRunErrorDesc();
                        item.count = 1;
                        appLog.getCrashs().add(item);
                    }
                }

                logger.info(device.getConnectAddress() + "generateLogReportEntity over");
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        logger.info(device.getConnectAddress() + " zyf:end collection logcat");
    }

    /**
     * generat log entity for post to server
     *
     * @param runLog    :所有的运行log
     * @param runAppLog ：仅仅是app相关的log
     * @param runAnrLog ：anr对应的/data/local/traces.txt文件
     */
    private void generateLogReportEntity(String runLog, String runAppLog, String runAnrLog) {
        try {

            FileInputStream fis = new FileInputStream(new File(runAppLog));
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    fis));

            FileInputStream fisAnr = null;
            BufferedReader readerAnr = null;
            File anrFile = new File(runAnrLog);
            if (anrFile.exists() && anrFile.length() != 0) {
                fisAnr = new FileInputStream(new File(runAnrLog));
                readerAnr = new BufferedReader(new InputStreamReader(fisAnr));
            }
            String anrLine;
            StringBuffer anrBuffer = new StringBuffer();
            String bufferLine;
            StringBuffer info = new StringBuffer();
            while ((bufferLine = reader.readLine()) != null) {
                if (bufferLine.trim().length() != 0
                        && bufferLine.contains("AndroidRuntime")
                        && bufferLine.contains("java.lang")
                        && bufferLine.contains("Exception")) {
                    // crash log
                    // 12-01 15:40:05.660 E/AndroidRuntime(24335):
                    // java.lang.NullPointerException: Attempt to invoke virtual
                    // method 'int java.lang.String.length()'
                    // 12-01 15:40:05.660 E/AndroidRuntime(24335): at
                    // com.abc.ThirdActivity.onClick(ThirdActivity.java:37)
                    String lineStart0 = bufferLine.substring(
                            bufferLine.indexOf("AndroidRuntime"),
                            bufferLine.length());

                    String lineStart1 = lineStart0.substring(
                            lineStart0.indexOf(":") + 1, lineStart0.length());
                    info.append(lineStart1);
                    String name = lineStart1.trim();
                    while ((bufferLine = reader.readLine()) != null
                            && bufferLine.contains("at ")) {
                        lineStart0 = bufferLine.substring(
                                bufferLine.indexOf("AndroidRuntime"),
                                bufferLine.length());
                        lineStart1 = lineStart0.substring(
                                lineStart0.indexOf(":") + 1,
                                lineStart0.length());
                        info.append(lineStart1);
                    }
                    int i = 0;
                    for (; i < appLog.getCrashs().size(); i++) {
                        Item item = appLog.getCrashs().get(i);
                        if (item.name.equals(name)
                                && item.detail.equals(info.toString())) {
                            item.count++;
                            break;
                        }
                    }
                    // not found
                    if (i == appLog.getCrashs().size()) {
                        Item crashItem = new Item();
                        crashItem.count = 1;
                        crashItem.detail = info.toString();
                        crashItem.name = name;
                        appLog.getCrashs().add(crashItem);
                    }
                    bufferLine = "";
                    info = new StringBuffer();
                }
                if (bufferLine.trim().length() != 0
                        && bufferLine.contains("System.err")
                        && bufferLine.contains("java.")
                        && bufferLine.contains("Exception")) {
                    String lineStart0 = bufferLine.substring(
                            bufferLine.indexOf("System.err"),
                            bufferLine.length());
                    String lineStart1 = lineStart0.substring(
                            lineStart0.indexOf(":") + 1, lineStart0.length());
                    logger.info(device.getConnectAddress() + " bufferLine:"
                            + bufferLine);
                    logger.info(device.getConnectAddress() + " lineStart0:"
                            + lineStart0);
                    logger.info(device.getConnectAddress() + " lineStart1:"
                            + lineStart1);
                    info.append(lineStart1);
                    String name = lineStart1.trim();
                    while ((bufferLine = reader.readLine()) != null
                            && bufferLine.contains("at ")) {
                        lineStart0 = bufferLine.substring(
                                bufferLine.indexOf("System.err"),
                                bufferLine.length());
                        lineStart1 = lineStart0.substring(
                                lineStart0.indexOf(":") + 1,
                                lineStart0.length());
                        info.append(lineStart1);
                    }
                    int i = 0;
                    for (; i < appLog.getExceptions().size(); i++) {
                        Item item = appLog.getExceptions().get(i);
                        if (item.name.equals(name)
                                && item.detail.equals(info.toString())) {
                            item.count++;
                            break;
                        }
                    }
                    // not found
                    if (i == appLog.getExceptions().size()) {
                        Item exceptionItem = new Item();
                        exceptionItem.count = 1;
                        exceptionItem.detail = info.toString();
                        exceptionItem.name = name;
                        // 有些crash信息的内容在System.err中也会进行输出，因此需要进行过滤
                        int j = 0;
                        for (; j < appLog.getCrashs().size(); j++) {
                            Item item = appLog.getCrashs().get(j);
                            if (item.name.equals(exceptionItem.name)
                                    && item.detail.equals(exceptionItem.detail)) {
                                break;
                            }
                        }
                        if (j == appLog.getCrashs().size()) {
                            appLog.getExceptions().add(exceptionItem);
                        }
                    }
                    bufferLine = "";
                    info = new StringBuffer();
                }

            }
            fis.close();
            reader.close();
            // anr部分分析需要使用全的log文件,拿到之后把相关log添加进AppLog对象中，并添加到run_app.log尾部。
            FileInputStream fisRun = new FileInputStream(new File(runLog));
            BufferedReader readerRun = new BufferedReader(
                    new InputStreamReader(fisRun));
            while ((bufferLine = readerRun.readLine()) != null) {

                if (bufferLine.trim().length() != 0
                        && bufferLine.contains("ANR in ")
                        && bufferLine.contains(apkFile.getPackageName())) {

                    logger.info(device.getConnectAddress()
                            + " zyf: found ANR in app_tmp.log");
                    FileOutputStream fos = new FileOutputStream(new File(
                            runAppLog), true);
                    BufferedWriter write = new BufferedWriter(
                            new OutputStreamWriter(fos));

                    String indexStart = "";
                    if (bufferLine.contains("ActivityManager")) {
                        indexStart = "ActivityManager";
                    } else if (bufferLine.contains("ANRManager")) {
                        indexStart = "ANRManager";
                    }
                    write.newLine();
                    write.write(bufferLine);
                    // 12-02 10:14:16.248 E/ANRManager( 823): ANR in
                    // com.modlebug1 (com.modlebug1/com.abc.FourActivity),
                    // time=213887565
                    // 12-02 10:14:16.248 E/ANRManager( 823): Reason: Input
                    // dispatching timed out (Waiting to send non-key event
                    // because the touched window has not finished processing
                    // certain input events that were delivered to it over
                    // 500.0ms ago. Wait queue length: 9. Wait queue head age:
                    // 8517.8ms.)
                    String lineStart0 = bufferLine
                            .substring(bufferLine.indexOf(indexStart),
                                    bufferLine.length());
                    String lineStart1 = lineStart0.substring(
                            lineStart0.indexOf(":") + 1, lineStart0.length());
                    info.append(lineStart1);
                    String name = lineStart1.trim();
                    // 把主log中关于anr部分添加到run_app.log的末位
                    while ((bufferLine = readerRun.readLine()) != null
                            && bufferLine.contains(indexStart)) {
                        write.newLine();
                        write.write(bufferLine);
                        if (bufferLine.contains("Reason:")) {
                            lineStart0 = bufferLine.substring(
                                    bufferLine.indexOf(indexStart),
                                    bufferLine.length());
                            lineStart1 = lineStart0.substring(
                                    lineStart0.indexOf(":") + 1,
                                    lineStart0.length());
                            info.append(lineStart1);
                        }
                    }
                    // anr的详细信息是需要从logcat和手机的/data/anr/traces.txt中读取合并出来的
                    // 可以参看/data/anr/traces.txt中内容进行分析
                    while (readerAnr != null
                            && (anrLine = readerAnr.readLine()) != null) {
                        if (anrLine.trim().length() != 0
                                && anrLine.contains("Cmd line:")
                                && anrLine.contains(apkFile.getPackageName())) { // crash
                            // log
                            anrBuffer.append(anrLine);
                            while ((anrLine = readerAnr.readLine()) != null
                                    && !anrLine.contains("JDWP")) {
                                anrBuffer.append(anrLine);
                            }
                        }
                    }
                    info.append(anrBuffer);
                    anrBuffer = new StringBuffer();

                    int i = 0;
                    for (; i < appLog.getAnr().size(); i++) {
                        Item item = appLog.getAnr().get(i);
                        if (item.name.equals(name)
                                && item.detail.equals(info.toString())) {
                            item.count++;
                            break;
                        }
                    }
                    // not found
                    if (i == appLog.getAnr().size()) {
                        Item anrItem = new Item();
                        anrItem.count = 1;
                        anrItem.detail = info.toString();
                        anrItem.name = name;
                        appLog.getAnr().add(anrItem);
                    }
                    bufferLine = "";
                    info = new StringBuffer();
                    // fos.close();
                    write.close();
                }
            }

            fisRun.close();
            readerRun.close();
            if (fisAnr != null) {
                fisAnr.close();
            }
            if (readerAnr != null) {
                readerAnr.close();
            }
            Gson gson = new Gson();
            String json = gson.toJson(appLog);
            logger.info(device.getConnectAddress() + " applog:json:"
                    + json.replace("\\t", "\n\t"));

        } catch (Exception e) {
            e.printStackTrace();
            logger.info(device.getConnectAddress() + " applog:json:exception");
        }
    }

    /**
     * perform monkey test. the test duration will be delay * repeat (msec).
     *
     * @param delay        interval of each monkey event
     * @param repeat       repeat times of monkey test
     * @param pctTouch     percent of touch event
     * @param pctMotion    percent of motion event
     * @param pctAppSwitch percent of activity switch event
     * @param pctSysKeys   percent of system key event
     * @param pctAnyEvent  percent of any other event
     * @return true success, false failure
     */
    protected boolean startMonkeyTest(long delay, long repeat, long pctTouch,
                                      long pctMotion, long pctAppSwitch, long pctSysKeys, long pctAnyEvent) {
        if (!checkDeviceWithStatusSet(false)) {
            return false;
        }
        String[] command = {ADB_COMMAND, "-s", connectAddress, "shell",
                " monkey -p", apkFile.getPackageName(),
                "--kill-process-after-error",
                "--monitor-native-crashes",
                "--ignore-native-crashes",
                "--ignore-crashes", "--ignore-timeouts",
                "--throttle", String.valueOf(delay),
                "--pct-touch", String.valueOf(pctTouch),
                "--pct-motion", String.valueOf(pctMotion),
                "--pct-appswitch", String.valueOf(pctAppSwitch),
                "--pct-syskeys", String.valueOf(pctSysKeys),
                "--pct-anyevent", String.valueOf(pctAnyEvent),
                "-s", String.valueOf(10 + new Random(System.currentTimeMillis()).nextInt(50)),
                "-v -v",
                String.valueOf(repeat)};
        logger.debug(device.getConnectAddress() + "  {}"+
                "monkey start, commond:" + Arrays.toString(command));
        CommandResult commandResult = ShellUtil
                .execCommand(command);

        logger.debug(device.getConnectAddress() + "  {}"+
                "zyf:monkey test over");
        boolean ret = true;
        String tag = "===== Run App Success =====\n";
        String runLog = deviceRootPath + "run.log";
        taskResult.setAppRunLog(StringUtil.removePrefix(runLog, removedPrefix));
        int result = AutomationResult.SUCCESS.getValue();
        String desc = commandResult.getResultMsg(); // by default
        BufferedReader reader = new BufferedReader(new StringReader(desc));
        try {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.contains("CRASH: " + apkFile.getPackageName())) {
                    desc = line;
                    result = AutomationResult.FAILURE.getValue();
                    tag = "===== Run App Crash Error =====\n";
                } else if (line.contains("NOT RESPONDING: "
                        + apkFile.getPackageName())) {
                    desc = line;
                    result = AutomationResult.FAILURE.getValue();
                    tag = "===== Run App ANR Error =====\n";
                } else if (line.contains("Long Msg:")) {
                    desc += line;
                    break;
                } else if (line.contains("ANR in " + apkFile.getPackageName())) {
                    desc += line;
                    result = AutomationResult.FAILURE.getValue();
                } else if (line.contains("Reason: ")) {
                    desc += line;
                    break;
                } else if (line.contains("java.lang.RuntimeException:")) {
                    desc += line;
                    result = AutomationResult.FAILURE.getValue();
                }else {
                    continue;
                }
                desc += GlobalConstants.SYMBOL_CRLF;
                logger.error("setAppRunLog : " + desc);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            try {
                reader.close();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }

        if("===== Run App ANR Error =====\n".equals(tag)){
            Item item = new Item();
            item.count += 1;
            item.detail = desc;
            item.name = desc;
            appLog.getAnr().add(item);
        }
        if("===== Run App Crash Error =====\n".equals(tag)){
            Item item = new Item();
            item.count += 1;
            item.detail = desc;
            item.name = desc;
            appLog.getCrashs().add(item);
            logger.error(" appLog.getCrashs() :  " + desc);
        }
        taskResult.setAppRun(result);
        logger.error("taskResult.setAppRun : " + result);
        logger.error("taskResult.setAppRunDesc :" + desc);
        if (result != AutomationResult.SUCCESS.getValue()) {
            ret = false;
            taskResult.setAppRunErrorDesc(desc.replace("//", ""));
            taskResult.setAppRunErrorLog(StringUtil.removePrefix(runLog,
                    removedPrefix));
        }
        String msg = "\n=============================================\n" + tag
                + commandResult.getResultMsg()
                + "\n=============================================\n";
        FileUtil.writeToFile(runLog, msg, true); // msg may too long which we  cannot use command 'echo' to print to file.
        logger.info(device.getConnectAddress()
                + " zyf:start collection run log");
        collectLogcat(runLog);

        return ret;
    }

    protected boolean isGetScreenShot = false;

    protected void startMonitor() {

        final int threadInterval = 20;

        final List<String> cpuUsages = new ArrayList<String>();
        taskResult.setCpuUsage(cpuUsages);
        final List<String> memoryUsages = new ArrayList<String>();
        taskResult.setMemoryUsage(memoryUsages);
        final List<String> pictureList = new ArrayList<>();
        taskResult.setScreenshots(pictureList);

        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {

                long screenshotInterval = GlobalConfig.getInstance()
                        .getScreenshotInterval();
                if (screenshotInterval > 8000) {
                    screenshotInterval = 8000;
                } else if (screenshotInterval < 2000) {
                    screenshotInterval = 2000;
                }
                // 内存和cpu获取间隔强制设定在3s-10s之间
                long performanceDumpInterval = GlobalConfig.getInstance()
                        .getPerformanceDumpInterval();
                if (performanceDumpInterval > 10000) {
                    performanceDumpInterval = 10000;
                } else if (performanceDumpInterval < 3000) {
                    performanceDumpInterval = 3000;
                }

                int count = 0;
                int picCount = 0;
                long lastTakenScreen = System.currentTimeMillis();
                long lastDumpCPU = System.currentTimeMillis();

                // update initial traffics (sent, recv)
                long[] oldTraffics = getTraffics();
                try {
                    while (!stopFlag.get()) {
                        long now = System.currentTimeMillis();
                        if (startAppFlag.get()
                                && ((now - lastTakenScreen) >= screenshotInterval)) {
                            CommandResult execCommand = ShellUtil.execCommandNoLog(new
                                    String[]{GlobalConstants.ADB_COMMAND, "-s", connectAddress,
                                    "shell", "dumpsys", "activity", "|", "grep", "mFocusedActivity"});
                            if (isGetScreenShot &&
                                    (!execCommand.isCommandSucceeded() || (execCommand.isCommandSucceeded() &&
                                            execCommand.getResultMsg().contains(apkFile.getPackageName())))) {
                                takeScreenshot(pictureList, picCount);
                                picCount++;
                                lastTakenScreen = System.currentTimeMillis();
                            } else if (isGetScreenShot && execCommand.isCommandSucceeded() &&
                                    execCommand.getResultMsg().contains(apkFile.getPackageName())) {
                                startApp(false);
                            }
                        }
                        now = System.currentTimeMillis();
                        if ((now - lastDumpCPU) >= performanceDumpInterval) {
                            lastDumpCPU = System.currentTimeMillis();
                            taskResult.getTest_time().add(
                                    DateUtils.getCurrentDate("HH:mm:ss"));

                            dumpCPU(cpuUsages);
                            DeviceBattery deviceBattery = getDeviceBattery();
                            taskResult.getTemperature_arr().add(
                                    deviceBattery.getTemperature());

                            dumpMemory(memoryUsages);

                            // update traffics
                            long[] currentTraffics = getTraffics();
                            long trafficDown = currentTraffics[0];
                            if (trafficDown > oldTraffics[0]) {
                                trafficDown -= oldTraffics[0];
                            } else {
                                trafficDown = 0;
                            }

                            long trafficUp = currentTraffics[1];
                            if (trafficUp > oldTraffics[1]) {
                                trafficUp -= oldTraffics[1];
                            } else {
                                trafficUp = 0;
                            }
                            logger.error("trafficDown : " + trafficDown + "  trafficUp: " + trafficUp);
                            taskResult.getTraffic_down_usage().add(
                                    String.valueOf(trafficDown));
                            taskResult.getTraffic_up_usage().add(
                                    String.valueOf(trafficUp));

                            logger.error("old_traffic_up : " + oldTraffics[0] + "old_traffic_down : " + oldTraffics[1] +
                                    "current_traffic_up : " + currentTraffics[0] + "current_traffic_down : " + currentTraffics[1]);
                            oldTraffics = Arrays.copyOf(currentTraffics,
                                    currentTraffics.length);
                        }

                        if (count % 5 == 0 && startAppFlag.get()) {
                            monitorAppAndRecordPid();
                            monitorActivityFront();
                            if (isLockScreen()) {
                                unLockScreenCrazy();
                            }
                        }

                        count++;
                        try {
                            synchronized (stopFlag) {
                                stopFlag.wait(threadInterval);
                            }
                        } catch (InterruptedException e) {
                            break;
                        }
                    }
                    logger.debug(device.getConnectAddress() + "  startMonitor over");
                    // remove unused pictures
                    String removedFiles = "";
                    int removedCount = 0;

                    while (pictureList.size() > 10) {
                        int pos = new Random().nextInt(pictureList.size() - 1);
                        removedFiles += removedPrefix + pictureList.remove(pos)
                                + " ";
                        removedCount++;
                    }

                    if (!StringUtil.isEmpty(removedFiles)) {
                        String[] command = {"sh", "-c",
                                "rm -rf " + removedFiles};
                        ShellUtil.execCommand(command);
                        logger.debug(device.getConnectAddress()
                                        + "  total remove {} unused pic files"+
                                removedCount);
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        });
        t.start();
    }

    /**
     * 监控测试的app对应activity位于栈顶(后续发现am start -n package/activity
     * 对应的activity必须是luanch和main标示的，否则命令出错) 因此此方法保留，并继续使用，用于检测
     */
    protected void monitorActivityFront() {
        try {
            String[] command = new String[]{
                    "sh",
                    "-c",
                    adbPath
                            + " -s "
                            + connectAddress
                            + " shell dumpsys activity activities  | grep '* Hist'"};
            CommandResult commandResult = ShellUtil
                    .execCommandNoLog(command);
            if (commandResult.isCommandSucceeded()
                    && commandResult.getResultMsg().trim().length() != 0) {
                String cmdResult = commandResult.getResultMsg().trim();
                String[] result = cmdResult.split("\n");

                if (result.length > 0) {
                    // 如果发现栈顶不是当前app的activity，进行操作
                    ArrayList<String> results = new ArrayList<String>(
                            Arrays.asList(result));
                    // 除去小米手机的影响
                    if (results.get(0).contains("com.miui.home"))
                        results.remove(0);

                    if (!results.get(0).contains(apkFile.getPackageName())) {
                        logger.info(device.getConnectAddress()
                                + " find app's activity background");
                        int i = 0;

                        for (; i < results.size(); i++) {
                            if (results.get(i).contains(
                                    apkFile.getPackageName())) {
                                logger.info(device.getConnectAddress()
                                        + " i found it to am start");
                                String line = results.get(i);
                                String line1 = line.substring(
                                        line.indexOf(apkFile.getPackageName()),
                                        line.length());
                                String packageActivityName = "";
                                if (line1.contains(" ")) {
                                    packageActivityName = line1.substring(0,
                                            line1.indexOf(" "));
                                } else if (line1.contains("}")) {
                                    packageActivityName = line1.substring(0,
                                            line1.indexOf("}"));
                                } else {
                                    i = results.size();
                                    break;
                                }
                                // 这种启动后台activity的方式有的app惯用，有的不管用
                                command = new String[]{adbPath, "-s",connectAddress, "shell", "am start -n",
                                        packageActivityName};
                                commandResult = ShellUtil.execCommand(command);
                                if (commandResult.isCommandSucceeded()
                                        && commandResult.getResultMsg()
                                        .contains("SecurityException")) {
                                    command = new String[]{
                                            adbPath,
                                            "-s",
                                            connectAddress,
                                            "shell",
                                            "am start -n",
                                            apkFile.getPackageName() + "/"
                                                    + apkFile.getActivityName()};
                                    commandResult = ShellUtil.execCommand(command);
                                    logger.info(device.getConnectAddress()
                                            + " am start -n commandResult:"
                                            + commandResult
                                            .isCommandSucceeded()
                                            + " msg:"
                                            + commandResult.getResultMsg());
                                }
                                break;
                            }
                        }
                        if (i == results.size()) {// 这种情况，app并没有结束，但是activitys栈里面确没有了相关app的activity，那么就启动他
                            logger.info(device.getConnectAddress()
                                    + " finally not found test app's activity to am start");
                            command = new String[]{
                                    "sh",
                                    "-c",
                                    adbPath + " -s " + connectAddress
                                            + " shell am start -S "
                                            + apkFile.getPackageName() + "/"
                                            + apkFile.getActivityName()};
                            ShellUtil.execCommand(command); // try to restart
                            logger.info(device.getConnectAddress()
                                    + " app not dead, but i have start it at all");
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.info(device.getConnectAddress() + " zyf:exception");
        }

    }

    /**
     * check app weather running ,if not restart
     * 监控获取app对应的pid号,把运行过程中app对应的pid都记录下来
     */
    protected void monitorAppAndRecordPid() {
        try {
            String[] command = new String[]{
                    "sh",
                    "-c",
                    adbPath + " -s " + connectAddress + " shell ps | grep "
                            + apkFile.getPackageName()};
            CommandResult commandResult = ShellUtil
                    .execCommandNoLog(command);
            if (!commandResult.getResultMsg()
                    .contains(apkFile.getPackageName())) {
                command = new String[]{
                        "sh",
                        "-c",
                        adbPath + " -s " + connectAddress
                                + " shell am start "
                                + apkFile.getPackageName() + "/"
                                + apkFile.getActivityName()};
                CommandResult cmdResult1 = ShellUtil
                        .execCommand(command);
                logger.info(device.getConnectAddress()
                        + " zyf:am start app command:cmdResult:isok:"
                        + cmdResult1.isCommandSucceeded());
            }

            String cmdResult = commandResult.getResultMsg().trim();
            String source = cmdResult.replaceAll(" +", " ");
            String[] dists = source.split(" ");
            if (dists.length < 2) {
                return;
            }
            if (!pids.contains(dists[1])) {
                pids.add(dists[1]);
                logger.info(device.getConnectAddress() + " pids:"
                        + pids.toString());
            }

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

    }

    /**
     * continuous to take screenshots till quit flag be set.
     * <p/>
     * adb shell screencap -p /sdcard/screen.png adb pull /sdcard/screen.png adb
     * shell rm /sdcard/screen.png
     * <p/>
     * w/o adb pull adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' >
     * screen.png adb shell screencap -p | perl -pi -e 's/\r\n/\n/g' >
     * screen.png
     */
    protected void takeScreenshot(final List<String> pictureList, int count) {
        try {
            turnOnScreen(); // keep screen on.
            String pictureName = deviceRootPath + "s_" + count + ".png";
            String[] command = {
                    "sh",
                    "-c",
                    adbPath
                            + " -s "
                            + connectAddress
                            + " shell screencap -p | perl -pe 's/\\x0D\\x0A/\\x0A/g' > "
                            + pictureName};
            CommandResult commandResult = ShellUtil
                    .execCommandNoLog(command);
            if (commandResult.isCommandSucceeded()) {
                logger.info(device.getConnectAddress() +
                        " screencap done {"+count+"}, save to file {}"+pictureName);
                File file = new File(pictureName);
                // black image leng less then 15000
                if (file.length() < 15000) {
                    file.delete();
                } else {
                    pictureList.add(StringUtil.removePrefix(pictureName,
                            removedPrefix));
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }

    }

    /**
     * 减音量
     */
    protected void setVolumeTo0() {
        for (int i = 0; i < 7; i++) {
            String[] command = {"sh", "-c",
                    adbPath + " -s " + connectAddress + " input keyevent  25"};
            ShellUtil.execCommandNoLog(command);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * dump CPU usage during the period.
     */

    protected void dumpCPU(final List<String> cpuUsages) {

        try {
            DecimalFormat df = new DecimalFormat("####0.00");
            double cpuPercent = 0.0;
            String[] command = {
                    "sh",
                    "-c",
                    adbPath + " -s " + connectAddress
                            + " shell dumpsys cpuinfo | grep "
                            + apkFile.getPackageName()};
            logger.info(Arrays.toString(command));
            CommandResult commandResult = ShellUtil.execCommandNoLog(command);
            if (commandResult.isCommandSucceeded()
                    && !StringUtil.isEmpty(commandResult.getResultMsg())) {
                String ret = commandResult.getResultMsg().replaceAll("\\s{2,}",
                        GlobalConstants.SYMBOL_SPACE).trim(); // remove multiple blank space.
                String[] results = ret.split(GlobalConstants.SYMBOL_SPACE);
                if (results.length > 0) {
                    try {
                        cpuPercent = Double.valueOf(results[0].trim()
                                .replace(GlobalConstants.SYMBOL_PCT, "")
                                .replace(GlobalConstants.SYMBOL_PLUS, "")
                                .replace(GlobalConstants.SYMBOL_DASH, ""));
                    } catch (NumberFormatException e) {
                        logger.error(e.getMessage());
                    }
                }
            }

            if (cpuPercent == 0) {
                // try second way to collect CPU usage.
                String[] topCommand = {
                        "sh",
                        "-c",
                        adbPath + " -s " + connectAddress
                                + " shell top -s cpu -n 1 -d 1 | grep "
                                + apkFile.getPackageName()};
                commandResult = ShellUtil.execCommandNoLog(topCommand);
                if (commandResult.isCommandSucceeded()
                        && !StringUtil.isEmpty(commandResult.getResultMsg())) {

                    String ret = commandResult.getResultMsg().replaceAll("\\s{2,}",
                            GlobalConstants.SYMBOL_SPACE).trim(); // remove multiple blank space.
                    String[] results = ret.split(GlobalConstants.SYMBOL_SPACE);
                    if (results.length > 0) {
                        try {
                            String cpuUseString = results[2].contains(GlobalConstants.SYMBOL_PCT) ? results[2] : results[3];

                            cpuPercent = Double.valueOf(cpuUseString.trim()
                                    .replace(GlobalConstants.SYMBOL_PCT, "")
                                    .replace(GlobalConstants.SYMBOL_PLUS, "")
                                    .replace(GlobalConstants.SYMBOL_DASH, ""));
                        } catch (NumberFormatException e) {
                            logger.error(e.getMessage());
                        }
                    }
                }
            }
            if (cpuPercent < 0.00) {
                cpuPercent = 0.00;
            } else if (cpuPercent > 100) {
                cpuPercent = 100;
            }
            cpuUsages.add(df.format(cpuPercent));
        } catch (Exception e) {
            logger.error("------dumpCPU   Exception \n" + e.getMessage());
        }
    }

    /**
     * dump memory usage during the period.
     */
    protected void dumpMemory(final List<String> memoryUsages) {
        int memInfo;
        try {
            String[] command = {adbPath, "-s", connectAddress, "shell",
                    "dumpsys meminfo", apkFile.getPackageName()};
            CommandResult commandResult = ShellUtil
                    .execCommandNoLog(command);
            if (commandResult.isCommandSucceeded()
                    && !StringUtil.isEmpty(commandResult.getResultMsg())) {
                String[] results = commandResult.getResultMsg().trim()
                        .split(GlobalConstants.SYMBOL_CRLF);
                for (String result : results) {
                    if (StringUtil.isEmpty(result)
                            || !result.trim().startsWith("TOTAL")) {
                        continue;
                    }
                    result = result.replaceAll("\\s{2,}",
                            GlobalConstants.SYMBOL_SPACE).trim();
                    String[] totalMemory = result
                            .split(GlobalConstants.SYMBOL_SPACE);
                    if (totalMemory.length > 1) {
                        try {
                            memInfo = Integer.valueOf(totalMemory[1].trim());
                            memoryUsages.add(String.valueOf(memInfo));
                        } catch (NumberFormatException e) {
                            logger.error(e.getMessage(), e);
                        }
                    }
                    break; // find it, break loop.
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * get network traffics for watched app.
     *
     * @return Array[0] received bytes, Array[1] sent bytes.
     */
    protected long[] getTraffics() {
        long[] traffics = {0, 0};
        int uid;

        try {
            String[] command = {
                    "sh",
                    "-c",
                    adbPath
                            + " -s "
                            + connectAddress
                            + " shell dumpsys package "
                            + apkFile.getPackageName()
                            + " | grep userId= | gawk '{ if(NR==1) {print $1;}}' | gawk -F '=' '{print $2;}'"};

            CommandResult commandResult = ShellUtil
                    .execCommandNoLog(command);
            if (commandResult.isCommandSucceeded()
                    && !StringUtil.isEmpty(commandResult.getResultMsg())) {
                uid = Integer.valueOf(commandResult.getResultMsg().trim());
                command = new String[]{
                        "sh",
                        "-c",
                        adbPath
                                + " -s "
                                + connectAddress
                                + " shell 'cat /proc/net/xt_qtaguid/stats'"
                                + " | grep "
                                + uid + " |grep -E 'wlan0|rmnet0'"
                                + " | gawk 'BEGIN {recv=0;sent=0;} {recv+=$6;sent+=$8;} END{print recv,sent;}'"};

                commandResult = ShellUtil.execCommand(command);
                if (commandResult.isCommandSucceeded()
                        && !StringUtil.isEmpty(commandResult.getResultMsg())) {
                    String[] data = commandResult.getResultMsg().split(
                            GlobalConstants.SYMBOL_SPACE);
                    traffics[0] = Long.valueOf(data[0].trim());
                    traffics[1] = Long.valueOf(data[1].trim());
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return traffics;
    }

    protected void disableDeviceSettingScreen() {
        Thread disableThread = new Thread(new Runnable() {
            @Override
            public void run() {
                int count = 0;
                while (!stopFlag.get() && count++ < 120) {
                    try {
                        String[] command = {adbPath, "-s", connectAddress,
                                "shell", "am", "broadcast -a disable_setting"};
                        ShellUtil.execCommandNoLog(command);

                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        break;
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    }
                }
            }
        });
        disableThread.setDaemon(true);
        disableThread.start();
    }

    /**
     * 尝试解锁画面. order:0,顺序1（先下上，后右左），1，顺序2（反之）(发现第一从右向左还是从下到上会直接影响效果)
     *
     * @return true unlocked, false failed to unlock.
     */
    public void unLockScreen(int order) {
        this.dispx = getScreenPx();
        logger.info(device.getConnectAddress() + " unlockType:" + unlockType);
        switch (unlockType) {
            case UNLOCK_SCREEN_DOWN_UP:
                upSwipeUnLock();
                break;
            case UNLOCK_SCREEN_LEFT_RIGHT:
                leftSwipeUnLock();
                break;
            case UNLOCK_SCREEN_RIGHT_LEFT:
                rightSwipeUnLock();
                break;
            case UNLOCK_SCREEN_CENTER_BOTTOM:
                centerToBottom();
                break;
            case UNLOCK_SCREEN_BOTTOM_LEFT_RIGHT:
                bottomLeftToRight();
                break;
            default:

                if (order == 0) {
                    // 尝试下上滑动解锁.
                    upSwipeUnLock();
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (!isLockScreen()) {
                        unlockType = UNLOCK_SCREEN_DOWN_UP;
                        return;
                    }

                    // 尝试右左滑动解锁.
                    rightSwipeUnLock();
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (!isLockScreen()) {
                        unlockType = UNLOCK_SCREEN_RIGHT_LEFT;
                        return;
                    }
                } else {
                    // 尝试右左滑动解锁.
                    rightSwipeUnLock();
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (!isLockScreen()) {
                        unlockType = UNLOCK_SCREEN_RIGHT_LEFT;
                        return;
                    }

                    // 尝试下上滑动解锁.
                    upSwipeUnLock();
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (!isLockScreen()) {
                        unlockType = UNLOCK_SCREEN_DOWN_UP;
                        return;
                    }

                }

                // 首先尝试左右滑动解锁.
                leftSwipeUnLock();
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!isLockScreen()) {
                    unlockType = UNLOCK_SCREEN_LEFT_RIGHT;
                    return;
                }

                // 中心向右滑動
                centerToright();
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!isLockScreen()) {
                    unlockType = UNLOCK_SCREEN_CENTER_RIGHT;
                    return;
                }

                centerToBottom();
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!isLockScreen()) {
                    unlockType = UNLOCK_SCREEN_CENTER_BOTTOM;
                    return;
                }

                bottomLeftToRight();
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!isLockScreen()) {
                    unlockType = UNLOCK_SCREEN_BOTTOM_LEFT_RIGHT;
                    return;
                }
                break;

        }
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    /**
     * 判定是否处于锁屏状态.
     *
     * @return true screen is locked status, false screen is unlocked status.
     */
    protected boolean isLockScreen() {

        String[] command = {
                "sh",
                "-c",
                adbPath + " -s " + connectAddress
                        + " shell dumpsys activity | grep -i mSleeping"};
        CommandResult commandResult = ShellUtil
                .execCommandNoLog(command);
        boolean ret = commandResult.isCommandSucceeded()
                && (commandResult.getResultMsg().contains(
                "mLockScreenShown=LOCK_SCREEN_SHOWN") || commandResult
                .getResultMsg().contains("mSleeping=true"));

        // logger.info(device.getConnectAddress() + " ret:" + ret);
        return ret;

    }

    /**
     * 向上滑动
     *
     * @return true swipe unlock successful, false failed.
     */
    public boolean upSwipeUnLock() {
        if (dispx == null) {
            String[] command = {adbPath, "-s", connectAddress, "shell",
                    "input swipe 200 1000 200 50"}; // power
            CommandResult commandResult = ShellUtil
                    .execCommand(command);
            return commandResult.isCommandSucceeded();
        } else {
            try {
                int x = Integer.parseInt(dispx[0]) / 2;
                int y1 = Integer.parseInt(dispx[1]) * 9 / 10;
                int y2 = Integer.parseInt(dispx[1]) / 6;
                String[] command = {adbPath, "-s", connectAddress, "shell",
                        "input swipe " + x + " " + y1 + " " + x + " " + y2}; // power
                CommandResult commandResult = ShellUtil
                        .execCommand(command);
                return commandResult.isCommandSucceeded();
            } catch (Exception e) {
                logger.info("up swipe to unlock screen for device : "
                        + connectAddress);
            }
            return false;
        }
    }

    /**
     * 获取屏幕分辨率
     *
     * @return true swipe unlock successful, false failed.
     */
    protected String[] getScreenPx() {

        try {
            // 通用方法获取（适用于所有手机）
            String[] command = new String[]{adbPath, "-s", connectAddress,
                    "shell", "dumpsys window displays"}; // power
            CommandResult commandResult = ShellUtil
                    .execCommandNoLog(command);

            String resultMsg = commandResult.getResultMsg();
            if (commandResult.isCommandSucceeded()) {

                String[] results = resultMsg.split(GlobalConstants.SYMBOL_CRLF);
                if (results.length > 0) {
                    for (int i = 0; i < results.length; i++) {
                        String line = results[i];
                        if (line.contains("init=") && line.contains("app=")) {
                            String subLine = line.substring(line
                                    .indexOf("init="));
                            String subLine1 = subLine
                                    .substring(subLine.indexOf("init=")
                                                    + "init=".length(),
                                            subLine.indexOf(" "));
                            String[] scrrenPx = subLine1
                                    .split(GlobalConstants.SYMBOL_x);
                            logger.info(device.getConnectAddress()
                                    + " displays scrrenPx:"
                                    + Arrays.toString(scrrenPx));
                            return scrrenPx;
                        }
                    }
                }
            }
            command = new String[]{
                    "sh",
                    "-c",
                    adbPath + " -s " + connectAddress
                            + " shell dumpsys window| grep -i init"};
            commandResult = ShellUtil.execCommandNoLog(command);

            resultMsg = commandResult.getResultMsg();
            if (commandResult.isCommandSucceeded()) {

                String resolution = resultMsg.substring(
                        resultMsg.indexOf('=') + 1,
                        resultMsg.indexOf(' '));
                String[] xes = resolution.split("x");
                logger.info(device.getConnectAddress()
                        + " grep -i init scrrenPx:" + Arrays.toString(xes));
                if (xes.length > 1) {
                    return xes;
                }
            }

            // 高通的cpu对应获取
            command = new String[]{adbPath, "-s", connectAddress, "shell",
                    "wm size"}; // power
            commandResult = ShellUtil.execCommandNoLog(command);

            resultMsg = commandResult.getResultMsg().replaceAll(" ", "");
            logger.info(device.getConnectAddress() + " result:" + resultMsg);
            if (commandResult.isCommandSucceeded()) {
                // 在vivo手机上会出现找不到命令并且还之行成功的情况
                if (resultMsg.contains("not found")) {
                    return null;
                }
                String[] results = resultMsg.split(GlobalConstants.SYMBOL_X);
                if (results.length < 2) {
                    results = resultMsg.split(GlobalConstants.SYMBOL_x);
                }
                logger.info(device.getConnectAddress() + " results[0]:"
                        + results[0]);
                results[0] = results[0].replace("Physicalsize:", "");

                if (results.length != 2)
                    return null;
                else
                    return results;
            } else
                return null;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return null;
        }
    }

    /**
     * 从中心向右滑动（如金立的一款手机（就是是个圈的解锁））
     *
     * @return true swipe unlock successful, false failed.
     */
    protected boolean centerToright() {
        if (dispx == null) {
            return false;
        }
        String x = dispx[0];
        String y = dispx[1];
        try {
            int intX = Integer.parseInt(x);
            int intY = Integer.parseInt(y);
            // executor.injectSwipe(deviceSign,intX/2,(intY/10)*8,intX,intY/10
            // *8);
            String[] command = {
                    adbPath,
                    "-s",
                    connectAddress,
                    "shell",
                    "input swipe " + intX / 2 + " " + (intY / 10) * 8 + " "
                            + intX + " " + intY / 10 * 8}; // power
            CommandResult commandResult = ShellUtil
                    .execCommand(command);
            return commandResult.isCommandSucceeded();

        } catch (NumberFormatException e) {
        }
        return false;
    }

    /**
     * （后米1s手机）
     *
     * @return true swipe unlock successful, false failed.
     */
    protected boolean centerToBottom() {
        if (dispx == null) {
            return false;
        }
        String x = dispx[0];
        String y = dispx[1];
        try {
            int intX = Integer.parseInt(x);
            int intY = Integer.parseInt(y);
            String[] command = {
                    adbPath,
                    "-s",
                    connectAddress,
                    "shell",
                    "input swipe " + intX / 2 + " " + (intY / 10) * 7 + " "
                            + intX / 2 + " " + intY}; // power
            CommandResult commandResult = ShellUtil
                    .execCommand(command);
            return commandResult.isCommandSucceeded();

        } catch (NumberFormatException e) {
        }
        return false;
    }

    /**
     * （vivo x510t）
     *
     * @return true swipe unlock successful, false failed.
     */
    protected boolean bottomLeftToRight() {
        if (dispx == null) {
            return false;
        }
        String x = dispx[0];
        String y = dispx[1];
        try {
            int intX = Integer.parseInt(x);
            int intY = Integer.parseInt(y);
            String[] command = {
                    adbPath,
                    "-s",
                    connectAddress,
                    "shell",
                    "input swipe " + intX / 8 + " " + (intY / 10) * 9 + " "
                            + intX * 8 / 10 + " " + intY / 10 * 9}; // power

            CommandResult commandResult = ShellUtil
                    .execCommand(command);
            return commandResult.isCommandSucceeded();

        } catch (NumberFormatException e) {
        }
        return false;
    }

    /**
     * 左右滑动
     *
     * @return true swipe unlock successful, false failed.
     */
    protected boolean leftSwipeUnLock() {

        if (dispx == null) {
            String[] command = {adbPath, "-s", connectAddress, "shell",
                    "input swipe 100 200 700 200"}; // power
            CommandResult commandResult = ShellUtil
                    .execCommand(command);
            return commandResult.isCommandSucceeded();
        } else {
            try {
                int x1 = Integer.parseInt(dispx[0]) * 2 / 10;
                int x2 = Integer.parseInt(dispx[0]) * 8 / 10;
                int y1 = Integer.parseInt(dispx[1]) / 2;
                int y2 = Integer.parseInt(dispx[1]) / 2;
                String[] command = {adbPath, "-s", connectAddress, "shell",
                        "input swipe " + x1 + " " + y1 + " " + x2 + " " + y2}; // power
                CommandResult commandResult = ShellUtil.execCommand(command);
                return commandResult.isCommandSucceeded();
            } catch (Exception e) {
                logger.info("left swipe to unlock screen for device : " + connectAddress);
            }
            return false;
        }
    }

    /**
     * 右左滑动
     *
     * @return true swipe unlock successful, false failed.
     */
    public boolean rightSwipeUnLock() {

        if (dispx == null) {
            String[] command = {adbPath, "-s", connectAddress, "shell",
                    "input swipe 700 200 100 200"}; // power
            CommandResult commandResult = ShellUtil
                    .execCommand(command);
            return commandResult.isCommandSucceeded();
        } else {
            try {
                int x1 = Integer.parseInt(dispx[0]) * 8 / 10;
                int x2 = Integer.parseInt(dispx[0]) * 2 / 10;
                int y1 = Integer.parseInt(dispx[1]) / 2;
                int y2 = Integer.parseInt(dispx[1]) / 2;
                String[] command = {adbPath, "-s", connectAddress, "shell",
                        "input swipe " + x1 + " " + y1 + " " + x2 + " " + y2}; // power
                CommandResult commandResult = ShellUtil.execCommand(command);
                return commandResult.isCommandSucceeded();
            } catch (Exception e) {
                logger.info("right swipe to unlock screen for device : " + connectAddress);
            }
            return false;
        }
    }

    /**
     * 进入桌面.
     *
     * @return true switch to home screen, false failed.
     */
    protected boolean toHome() {
        String[] command = {adbPath, "-s", connectAddress, "shell",
                "input keyevent 3"};
        CommandResult commandResult = ShellUtil.execCommand(command);
        return commandResult.isCommandSucceeded();
    }

    protected boolean unLockScreenCrazy() {
        int i = 0;
        for (i = 0; i < 4; i++) {
            turnOnScreen();
            // UnLock Screen
            unLockScreen(0);
            // go home
            toHome();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (!isLockScreen()) {
                return true;
            }
        }
        if (i == 4) {
            for (i = 0; i < 4; i++) {
                turnOnScreen();
                // UnLock Screen
                unLockScreen(1);
                // go home
                toHome();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!isLockScreen()) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 去掉另一个监控app中点击事件（如果sdkVersion == 21）
     */
    protected void clearClickBroadcast() {
        if (sdkVersion == 21 && startMonkeyTest.get() == false) {
            // 事先手机上装了一个apk用来处理安装时候的弹出框问题
            String[] command = {adbPath, "-s", connectAddress, "shell",
                    "am broadcast -a set.flag.null"};
            ShellUtil.execCommand(command);
        }
    }

    /**
     * NOTE: required sdk >= 16
     */
    protected Thread doDialogCheckParalleled(final boolean systemOnly) {
        if (sdkVersion < 16) {
            return null;
        }
        if (sdkVersion == 21 && startMonkeyTest.get() == false) {
            // 事先手机上装了一个apk用来处理安装时候的弹出框问题
            String[] command = {adbPath, "-s", connectAddress, "shell",
                    "am broadcast -a set.flag.allways.true"};
            ShellUtil.execCommand(command);
        }

        Thread t = new Thread() {
            @Override
            public void run() {
                try {
                    logger.info(device.getConnectAddress()
                            + " >> start install Check >>");
                    int maxCheckCount = 0;
                    // 提取画面.
                    Coordinate coordinate = new Coordinate();
                    // 如果安装和打开没有异常，一直等待画面打开和热身完毕。一直在检测.
                    while (!startMonkeyTest.get()) {
                            service.refresh();
                            UiDumpModel model = null;
                            model = findElementByKeyword(service, GlobalConstants.KEYWORDS_SYSTEM_POPUP_WINDOW,
                                    systemOnly ? GlobalConstants.KEYWORD_SYSTEM_PACKAGE_NAME : null);
                            coordinate = model != null ? model.getCoordinate() : null;
                            Thread.sleep(2000L);
                            // 出现选择性控件，处理之./
                            if (coordinate != null) {
                                logger.error(connectAddress + " tap UiDumpModel:" + model.getText());
                                tap(coordinate.getX(), coordinate.getY());
                            }
                            try {
                                Thread.sleep(500);
                            } catch (InterruptedException e) {
                                break;
                            }
                        }
                    logger.info(device.getConnectAddress()
                            + " >> done install Check >>");
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        };
        t.start();
        return t;
    }

    /**
     * 处理引导页.
     */
    protected void doWizardPage() {
        try {
            // 左滑5下.
            for (int i = 0; i < 6; i++) {
                leftSwipeUnLock();
                Thread.sleep(1000);
            }
            // 如果当前设备支持uiautomator。如果还处于引导页，找到第一个可点击控件。点击进入主画面.
            if (sdkVersion >= 16) {
                service.refresh();
                // 如果当前画面有viewpager，认为还处于引导页.
                Coordinate click = null;
                UiDumpModel viewPager = service
                        .findElementByClass(GlobalConstants.CLASS_TYPE_VIEW_PAGER);
                if (viewPager == null) {
                    viewPager = service
                            .findElementByClass(GlobalConstants.CLASS_TYPE_SCROLL_VIEW);
                }

                UiDumpModel clickBtn = service.findLastButton();
                logger.debug(device.getConnectAddress()
                        + "  viewPager: {},"+ viewPager+"       clickBtn: {}"+ clickBtn);

                if (clickBtn != null && viewPager != null) {
                    click = clickBtn.getCoordinate();
                    if (click != null) {
                        tap(click.getX(), click.getY());
                    }
                }
            }
        } catch (Exception e) {
            logger.warn(">> doWizardPage error {}."+e.getMessage(), e);
        }
    }

    /**
     * 根据传入的关键字集合，分析当前画面是否包含指定关键字。
     *
     * @param service  ui automator handler
     * @param keyWords whitelist
     * @return UiDumpModel
     */
    protected UiDumpModel findElementByKeyword(
            UiAutomatorHandlerService service, String[] keyWords,
            String packageName) {
        UiDumpModel modle = null;
        for (String keyWord : keyWords) {
            modle = service.findElementByKeyword(keyWord, packageName, sdkVersion);
            if (modle != null) {
                return modle;
            }
        }
        return  null;
    }

    /**
     * 点击坐标点.
     *
     * @param x position X
     * @param y position Y
     */
    protected boolean tap(int x, int y) {
        String[] command = {adbPath, "-s", connectAddress, "shell", "input tap ", x + "", y + ""};
        CommandResult commandResult = ShellUtil.execCommand(command);
        return commandResult.isCommandSucceeded();
    }

    /**
     * 在当前光标处输入指定的文字。
     *
     * @param text which text send to device
     * @return true successful, false failure
     */
    protected boolean inputText(String text) {
        String[] command = {adbPath, "-s", connectAddress, "shell",
                "input text", text};
        CommandResult commandResult = ShellUtil.execCommand(command);

        return commandResult.isCommandSucceeded();
    }

    /**
     * get device battery info.
     *
     * @return DeviceBattery
     */
    protected DeviceBattery getDeviceBattery() {
        DeviceBattery deviceBattery = new DeviceBattery();
        String[] command = {adbPath, "-s", connectAddress, "shell",
                "dumpsys battery"};
        CommandResult commandResult = ShellUtil.execCommandNoLog(command);
        if (!commandResult.isCommandSucceeded()) {
            return deviceBattery;
        }
        String[] results = commandResult.getResultMsg().split(
                GlobalConstants.SYMBOL_CRLF);
        for (String result : results) {
            try {
                if (StringUtil.isEmpty(result.trim())) {
                    continue;
                }
                String[] tmpArray = result.split(GlobalConstants.SYMBOL_COLON);
                if (tmpArray.length < 2) {
                    continue;
                }
                String key = tmpArray[0].trim();
                String value = tmpArray[1].trim();
                if (key.contains(DeviceBattery.key_ACPowered)) {
                    deviceBattery.setAcPowered(value);
                } else if (key.contains(DeviceBattery.key_USBPowered)) {
                    deviceBattery.setUsbPowered(value);
                } else if (key.contains(DeviceBattery.key_WirelessPowered)) {
                    deviceBattery.setWirelessPowered(value);
                } else if (key.contains(DeviceBattery.key_Overload)) {
                    deviceBattery.setOverload(value);
                } else if (key.contains(DeviceBattery.key_USBOverheat)) {
                    deviceBattery.setUsbOverheat(value);
                } else if (key.contains(DeviceBattery.key_Extension)) {
                    deviceBattery.setExtension(value);
                } else if (key.contains(DeviceBattery.key_PowerJacketExist)) {
                    deviceBattery.setPowerJacketExist(value);
                } else if (key.contains(DeviceBattery.key_PowerJacketStatus)) {
                    deviceBattery.setPowerJacketStatus(value);
                } else if (key.contains(DeviceBattery.key_PowerJacketLevel)) {
                    deviceBattery.setPowerJacketLevel(value);
                } else if (key.contains(DeviceBattery.key_PluginStatus)) {
                    deviceBattery.setPluginStatus(value);
                } else if (key.contains(DeviceBattery.key_UnSupportCharger)) {
                    deviceBattery.setUnSupportCharger(value);
                } else if (key.contains(DeviceBattery.key_status)) {
                    deviceBattery.setStatus(value);
                } else if (key.contains(DeviceBattery.key_health)) {
                    deviceBattery.setHealth(value);
                } else if (key.contains(DeviceBattery.key_present)) {
                    deviceBattery.setPresent(value);
                } else if (key.contains(DeviceBattery.key_level)) {
                    deviceBattery.setLevel(value);
                } else if (key.contains(DeviceBattery.key_scale)) {
                    deviceBattery.setScale(value);
                } else if (key.contains(DeviceBattery.key_voltage)) {
                    deviceBattery.setVoltage(value);
                } else if (key.contains(DeviceBattery.key_temperature)) {
                    deviceBattery.setTemperature(value);
                } else if (key.contains(DeviceBattery.key_technology)) {
                    deviceBattery.setTechnology(value);
                } else {
                    // do nothing.
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        try {
            int level = Integer.valueOf(deviceBattery.getLevel());
            int scale = Integer.valueOf(deviceBattery.getScale());
            int voltage = Integer.valueOf(deviceBattery.getVoltage());
            int temperature = Integer.valueOf(deviceBattery.getTemperature());
            deviceBattery.setLevel(String.valueOf(level / scale * 100));
            deviceBattery.setVoltage(String.valueOf(voltage / 1000));
            deviceBattery.setTemperature(String.valueOf(temperature / 10));
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return deviceBattery;
    }


    protected int getSdkVersion() {
        String[] command = {adbPath, "-s", connectAddress, "shell",
                "getprop ro.build.version.sdk"};
        CommandResult commandResult = ShellUtil.execCommand(command);

        if (commandResult.isCommandSucceeded()) {
            try {
                return Integer.parseInt(commandResult.getResultMsg().trim());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return 0;
    }
}
